package com.le.tester.webpage.redis.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.le.tester.common.Const;
import com.le.tester.common.enums.RedisKey;
import com.le.tester.delay.DelayedOrder;
import com.le.tester.delay.OnDelayedListener;
import com.le.tester.entity.Order;
import com.le.tester.utils.DateTimeUtilFor8;
import com.le.tester.utils.RedisUtil;
import com.le.tester.utils.ThreadPoolUtil;
import com.le.tester.webpage.redis.service.DelayedService;
import com.le.tester.webpage.redis.service.RedisOrderAutoConfirmService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 描述：自动确认订单实现类
 */
@Service
public class RedisOrderAutoConfirmServiceImpl implements RedisOrderAutoConfirmService {

    private static final Logger LOG = LoggerFactory.getLogger(RedisOrderAutoConfirmServiceImpl.class);

    @Autowired
    private RedisUtil redisUtil;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private DelayedService delayedService;

    /**
     * 订单支付
     *
     * @param orderId 订单id
     * @return
     */
    @Override
    public DelayedOrder createOrder(String orderId) {
        Order order = new Order();
        order.setOrderId(orderId);
        //默认的状态0，未支付
        order.setStatus(0);
        order.setCreateTime(DateTimeUtilFor8.epochMilli());
        LOG.info("订单{}创建完成，插入数据库,", orderId);
        //baseDelayedQueue多乘以了1000，value是这个订单编号,timeoutSeconds是监听的频率每timeoutSeconds进行监听
        DelayedOrder delayedOrder = new DelayedOrder((long) 3 * 60, orderId);
        //插入到内存队列
        delayedService.add(delayedOrder);
        //插入到redis
        //创建一个hash
        BoundHashOperations<String, Object, Object> hashOps = redisUtil.boundHashOps(RedisKey.ORDERS.getCode());
        //这里是hash中的key
        hashOps.put(orderId, order);
        //测试redis,把前面的hashKey覆盖了
        //redisUtil.set(RedisKey.ORDERS.getCode(), order);
        //this.addToSet(RedisKey.ORDERS.getCode(), order);
        return delayedOrder;
    }

    /**
     * 订单支付
     *
     * @param orderId 订单id
     * @return
     */
    @Override
    public boolean payOrder(String orderId) {
        Order order = getFormDb(orderId);
        order.setOrderId(orderId);
        //支付成功
        order.setStatus(1);
        LOG.info("订单{}支付完成", orderId);
        //根据订单号获取延时队列中的信息
        DelayedOrder delayed = delayedService.getDelayed(DelayedOrder.class, orderId);
        if (delayed != null) {
            //支付成功，从队列中删除
            LOG.info("支付成功，从队列中删除信息");
            delayedService.remove(DelayedOrder.class, delayed);
            //支付成功，从redis中删除
            LOG.info("支付成功，从redis中删除信息");
            redisUtil.hdel(RedisKey.ORDERS.getCode(), orderId);

        }
        return true;
    }

    /**
     * 自动取消订单
     *
     * @param delayedOrder 延迟订单信息
     * @return
     */
    public boolean autoCancelOrder(DelayedOrder delayedOrder) {
        String orderId = delayedOrder.getValue();
        Order order = this.getFormDb(orderId);
        order.setOrderId(orderId);
        //取消
        order.setStatus(2);
        LOG.info("修改订单{}为已取消", orderId);
        //延迟队列中的订单
        LOG.info("从队列中删除该订单:{}", orderId);
        delayedService.remove(DelayedOrder.class, delayedOrder);
        //删除redis的中存在的订单,使用的是hashKey
        LOG.info("从redis中删除该订单:{}", orderId);
        redisUtil.hdel(RedisKey.ORDERS.getCode(), orderId);
        return true;

    }

    //根据订单号码获取订单信息(模拟数据库)
    private Order getFormDb(String orderId) {
        Order order = new Order();
        order.setOrderId(orderId);
        return order;
    }

    //启动spring 的时候就会调用该方法，并不会多次调用
    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info("redisOrderAuto afterPropertiesSet当前的时间：{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern(Const.STANDARD_FORMAT)));
        //启动注册监听，对队列里的进行监听，因为启动了监听，会多次调用
        delayedService.registerListen(DelayedOrder.class, new OnDelayedListener<DelayedOrder>() {
            @Override
            public void onDelayedArrived(DelayedOrder delayed) {
                LOG.info("redisOrderAuto onDelayedArrived当前的时间：{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern(Const.STANDARD_FORMAT)));
                LOG.info("redisOrderAuto onDelayedArrived{}", delayed);
                //查询订单状态
                String orderId = delayed.getValue();
                int status = getFormDb(orderId).getStatus();
                if (status == 0) {
                    //未支付，刚刚创建
                    autoCancelOrder(delayed);
                } else if (status == 1) {
                    //已经支付
                    LOG.info("订单{}已经支付", orderId);

                } else if (status == 2) {
                    //用户主动取消
                    LOG.info("取消订单{}", orderId);

                }

            }
        });
        //把redis中的订单重新插入延时队列
        //application is shutDown 重新把redis中的订单放进队列进行操作
        ThreadPoolUtil.execute(() -> {
            LOG.info("redisOrderAuto ThreadPool当前的时间：{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern(Const.STANDARD_FORMAT)));
            Map<Object, Object> hmGet = redisUtil.hmget(RedisKey.ORDERS.getCode());
            if (!CollectionUtils.isEmpty(hmGet)) {
                Set<Object> order = hmGet.keySet();
                for (Object orderIdItem : order) {
                    JSONObject orderVal = JSONObject.parseObject(String.valueOf(hmGet.get(String.valueOf(orderIdItem))));
                    LOG.info("orderVal:{}", orderVal);
                    long createTime = ((long) orderVal.get("createTime"));
                    long currTime = (DateTimeUtilFor8.epochMilli());
                    //订单创建20分钟后(测试的时候使用的是3分钟)
                    long lateTime = createTime + (3 * 60 * 1000);
                    long resultTime = (lateTime - currTime) / 1000;
                    //可以从数据库中获取订单信息，包括订单创建的时间
                    //出现在这里的resultTime，只会是大于0
                    DelayedOrder delayedOrder = new DelayedOrder(resultTime, String.valueOf(orderIdItem));
                    delayedService.add(delayedOrder);
//                }
//            }
//            List<DelayedOrder> delayedOrders = getFromSet(RedisKey.ORDERS.getCode(), DelayedOrder.class);
//            if (!CollectionUtils.isEmpty(delayedOrders)) {
//                for (DelayedOrder order : delayedOrders) {
//                    delayedService.add(order);
                }
            }
        });

    }

    @SuppressWarnings("unchecked")
    public <T> List<T> getFromSet(String key, Class<T> valueClazz) {
        BoundSetOperations<String, T> operations = (BoundSetOperations<String, T>) redisTemplate.boundSetOps(key);
        Set<T> mems = operations.members();
        return new ArrayList<T>(mems);
    }

    @SuppressWarnings("unchecked")
    public <T> boolean addToSet(String key, T value) {
        BoundSetOperations<String, T> operations = (BoundSetOperations<String, T>) redisTemplate.boundSetOps(key);
        operations.add(value);
        return true;
    }

}
